package com.lili.collection.mq.utils;

import com.lili.collection.core.fields.Field;
import com.lili.collection.core.record.Record;
import com.lili.collection.core.runner.result.ErrorDetail;
import com.lili.collection.core.runner.result.RecordInfo;
import com.lili.collection.mq.domain.ByteMessageWrapper;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *描述: json数据转换为数据库保存的数据格式
 *@date:2023/3/2  20:44
 *@author:lili
 */
@Slf4j
public class JsonConvertUtil {

    /**
     * Record记录转换为JSON格式数据
     * @param output 输出格式数据
     * @return
     */
    public static byte[] convertRecordToJsonByte(List<Record> output, RecordInfo recordInfo){
        if(CollectionUtils.isEmpty(output)){
            return null;
        }
        List<JSONObject> lastJsonList=new ArrayList<>();
        for (Record record : output) {
            try {
                Map<String, Field> row = record.getField().getValueAsMap();
                JSONObject jsonObject=new JSONObject(row.size());
                for (String fieldName : row.keySet()) {
                    jsonObject.put(fieldName,row.get(fieldName).getValue());
                }
                lastJsonList.add(jsonObject);
                recordInfo.incrementSuccessCount();
            } catch (Throwable throwable) {
                log.error("json转换异常!", throwable);
                recordInfo.incrementErrorCount();
                throw throwable;
            }finally {
                recordInfo.incrementTotalCount();
            }
        }
        String data = JSON.toJSONString(lastJsonList,"yyyy-MM-dd HH:mm:ss", JSONWriter.Feature.WriteMapNullValue);
        if(StringUtils.isBlank(data)){
            throw new IllegalArgumentException("JSON转换的数据不能为空!");
        }
        return data.getBytes(StandardCharsets.UTF_8);
    }

    /**
     * List数据进行切分
     * @param output 原始数据
     * @param recordInfo 记录信息
     * @param maxMessageSize 最大消息大小
     * @param isThrowException 是否抛出异常:true:直接抛出异常,false:记录错误信息
     * @return
     */
    public static List<ByteMessageWrapper> convertRecordToJsonByteWrapper(List<Record> output, RecordInfo recordInfo, int maxMessageSize, boolean isThrowException) {
        if (CollectionUtils.isEmpty(output)) {
            return null;
        }
        List<JSONObject> lastJsonList = new ArrayList<>();
        for (Record record : output) {
            try {
                Map<String, Field> row = record.getField().getValueAsMap();
                JSONObject jsonObject = new JSONObject(row.size());
                for (String fieldName : row.keySet()) {
                    jsonObject.put(fieldName, row.get(fieldName).getValue());
                }
                lastJsonList.add(jsonObject);
                if(isThrowException){
                    recordInfo.incrementSuccessCount();
                }
            } catch (Throwable throwable) {
                if(isThrowException){
                    recordInfo.incrementErrorCount();
                }
                log.error("json转换异常!", throwable);
                throw throwable;
            } finally {
                recordInfo.incrementTotalCount();
            }
        }
        String data = JSON.toJSONString(lastJsonList, "yyyy-MM-dd HH:mm:ss", JSONWriter.Feature.WriteMapNullValue);
        if (StringUtils.isBlank(data)) {
            throw new IllegalArgumentException("JSON转换的数据不能为空!");
        }
        List<ByteMessageWrapper> wrapperList = new ArrayList<>();
        byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
        if (bytes.length > maxMessageSize && maxMessageSize > 0) {
            int initAbleSplitNum = (lastJsonList.size() / MQUtil.splitNum(bytes.length, maxMessageSize));
            splitJsonList(maxMessageSize, lastJsonList, wrapperList, initAbleSplitNum,isThrowException,recordInfo);
        } else {
            wrapperList.add(new ByteMessageWrapper(bytes,data,lastJsonList.size()));
        }
        return wrapperList;
    }

    /**
     * 明细切分方法
     * @param maxMessageSize 有效最大数据量
     * @param lastJsonList 原始JSON数组
     * @param wrapperList 已拆分的封装字节数据
     * @param initAbleSplitNum 初始化切分大小
     * @param isThrowException 是否抛出异常:true:直接抛出异常,false:记录错误信息
     * @param recordInfo 记录点
     */
    private static void splitJsonList(int maxMessageSize, List<JSONObject> lastJsonList, List<ByteMessageWrapper> wrapperList, int initAbleSplitNum,boolean isThrowException,RecordInfo recordInfo) {
        initAbleSplitNum=(initAbleSplitNum<=0?1:initAbleSplitNum);
        for (List<JSONObject> partitionList :  Lists.partition(lastJsonList, initAbleSplitNum)) {
            String partitionData = JSON.toJSONString(partitionList, "yyyy-MM-dd HH:mm:ss", JSONWriter.Feature.WriteMapNullValue);
            byte[] partitionBytes = partitionData.getBytes(StandardCharsets.UTF_8);
            if (partitionBytes.length > maxMessageSize) {
                if (initAbleSplitNum == 1) {
                    if(isThrowException){
                        throw new IllegalArgumentException("当前json数据量为["+partitionBytes.length+"]大于有效["+maxMessageSize+"]字节，无法进行拆分数据！");
                    }else {
                        recordInfo.setSuccessed(false);
                        recordInfo.incrementErrorCount();
                        String errorMsg="java.lang.IllegalArgumentException:当前json数据量大于有效["+maxMessageSize+"]字节，无法进行拆分数据！";
                        recordInfo.getErrOutputData().putErrorInfo(errorMsg);
                        recordInfo.addErrorValueDetail(new ErrorDetail("JSON",partitionData,errorMsg,partitionBytes.length));
                    }
                }else if (initAbleSplitNum >= 2){
                    splitJsonList(maxMessageSize, partitionList, wrapperList, initAbleSplitNum / 2,isThrowException,recordInfo);
                }
            }else {
                wrapperList.add(new ByteMessageWrapper(partitionBytes,partitionData,partitionList.size()));
            }
        }
    }
}